/*
 *  *  Written by Xing Jing     */
/*
 * $Id: lsv_op.c $
 */
#define FUSE_USE_VERSION 30

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef linux
/* For pread()/pwrite() */
#define _XOPEN_SOURCE 500
#endif

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#include <sys/time.h>
#ifdef HAVE_SETXATTR
#include <sys/xattr.h>
#endif
#include <sys/ioctl.h>
#include <fuse.h>
#include "list.h"

#include  "lsv_conf.h"
#include "lsv_types.h"
#include "lsv_volume_proto.h"
#include "lsv_op.h"
#include "lsv_help.h"
#include "lsv_conf.h"
#include "lsv_bitmap.h"
#include "lsv_log.h"
#include "lsv_volume.h"
#include "lsv_utils.h"
#include "lsv_bitmap_snap.h"

#include "volume_proto.h"

int lsv_statfs(const char *path, struct statvfs *stbuf) {
	int rc = 0;

	(void) path;
	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	struct statvfs stbuf123;

	DINFO("lsv_statfs:enter:%s\n", path);

	rc = statvfs(path_name, stbuf);
	stbuf->f_frsize = 4096;
	stbuf->f_namemax = 255;
	DINFO("lsv_statfs:f_bsize:%d\n", stbuf->f_bsize);
	DINFO("lsv_statfs:f_frsize:%d\n", stbuf->f_frsize);
	DINFO("lsv_statfs:f_blocks:%llu\n", stbuf->f_blocks);
	DINFO("lsv_statfs:f_bfree:%llu\n", stbuf->f_bfree);
	DINFO("lsv_statfs:f_bavail:%llu\n", stbuf->f_bavail);
	DINFO("lsv_statfs:f_files:%d\n", stbuf->f_files);
	DINFO("lsv_statfs:f_ffree:%d\n", stbuf->f_ffree);
	DINFO("lsv_statfs:f_ffavail:%d\n", stbuf->f_favail);
	DINFO("lsv_statfs:f_fsid:%d\n", stbuf->f_fsid);
	DINFO("lsv_statfs:f_fla    :%d\n", stbuf->f_flag);
	DINFO("lsv_statfs:f_namemax:%d\n", stbuf->f_namemax);
	/*
	 */
	DINFO("lsv_statfs:exit,rc:%d\n", rc);

	return 0;
}

int lsv_open(const char *path, struct fuse_file_info *fi) {
	lsv_s32_t rc = 0;
	ino_t ino;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_open:enter:%s\n", path_name);
	rc = stat(path_name, &stbuf);
	if (rc == 0) {
		ino = stbuf.st_ino;
		rc = lsv_volumep_lookup(ino, &volume_proto);
		if (rc != 0) {
			DINFO("lsv_open:init exist volume:%s,rc:%d\n", path_name, rc);
			rc = lsv_volumep_load(ino, &volume_proto);
			if (rc < 0) {
				DINFO("lsv_open:load volumep error:%d\n", rc);
				return rc;
			}

			rc = lsv_initialize(volume_proto, LSV_SYS_LOAD);
			if (rc < 0) {
				return rc;
			}
		}
	} else {
		DINFO("lsv_open:volume not exist:%s\n", path_name);
	}

	return 0;
}

static int lsv_access(const char *path, int mask) {
	int rc;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	rc = access(path_name, mask);
	if (rc == -1)
		return -errno;

	return 0;
}

static int lsv_mknod(const char *path, mode_t mode, dev_t rdev) {
	int rc0 = 0;
	int rc = 0;
	int fd = 0;
	int ino = 0;
	lsv_u64_t volume_size = 0;
	struct stat stbuf;
	struct statvfs stbufvfs;
	lsv_volume_proto_t *volume_proto = NULL;
	lsv_u32_t first_chkid = 0;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_mknod:enter:%s\n", path_name);

	/* On Linux this could just be 'mknod(path, mode, rdev)' but this
	 is more portable */
	if (S_ISREG(mode)) {
		rc0 = open(path_name, O_CREAT | O_EXCL | O_WRONLY, mode);
		if (rc0 >= 0)
			rc0 = close(rc0);
	} else if (S_ISFIFO(mode))
		rc0 = mkfifo(path_name, mode);
	else
		rc0 = mknod(path_name, mode, rdev);
	if (rc0 == -1)
		return -errno;

	rc = stat(path_name, &stbuf);

	rc = statvfs(path_name, &stbufvfs);
	volume_size = stbufvfs.f_bsize * stbufvfs.f_blocks;
	volume_size = volume_size * LSV_STORAGE_AVA_RATIO;

	ino = stbuf.st_ino;

	rc = lsv_volumep_create(ino, volume_size, &volume_proto);
	if (rc < 0) {
		return rc;
	}

	rc = lsv_initialize(volume_proto, LSV_SYS_CREATE);
	if (rc < 0) {
		return rc;
	}

	DINFO("lsv_mknod:exit\n");

	return rc0;
}

int lsv_unlink(const char *path) {
	int rc = 0;
	ino_t ino;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_unlink:enter:%s\n", path);

	rc = stat(path_name, &stbuf);
	ino = stbuf.st_ino;
	rc = lsv_volumep_lookup(ino, &volume_proto);
	if (stbuf.st_nlink == 1) {
		DINFO("lsv_unlink:%llu will be removed.%s\n", ino, path);
		list_del(&(volume_proto->vp_list));
		rc = lsv_finalize_vp(volume_proto);
		if (rc < 0) {
			DINFO("lsv_unlink:finalize vp %llu, %s error.\n", ino, path);
		}
	}

	rc = unlink(path_name);
	if (rc == -1)
		return -errno;

	/*Release all the */

	return rc;
}

int lsv_flush(const char *path, struct fuse_file_info *fi) {
	int rc = 0, i = 0;
	ino_t ino;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	rc = stat(path_name, &stbuf);
	ino = stbuf.st_ino;
	rc = lsv_volumep_lookup(ino, &volume_proto);

	DINFO("flush :%d\n", ino);

	return rc;
}

int lsv_release(const char *path, struct fuse_file_info *fi) {
	int rc = 0;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_release:enter:%s\n", path_name);

	return rc;
}

int lsv_getattr(const char *path, struct stat *stbuf) {
	int rc = 0;
	ino_t ino;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_getattr:enter:%s\n", path_name);

	rc = stat(path_name, stbuf);
	if (rc == 0) {
		ino = stbuf->st_ino;
		rc = lsv_volumep_lookup(ino, &volume_proto);
		if (rc != 0) {
			DINFO("lsv_getattr:init exist volume:%s,rc:%d,ino:%llu\n",
					path_name, rc, ino);
			rc = lsv_volumep_load(ino, &volume_proto);
			if (rc < 0) {
				DINFO("lsv_getattr:load volumep error:%d\n", rc);
				return 0;
			}

			rc = lsv_initialize(volume_proto, LSV_SYS_LOAD);
			if (rc < 0) {
				return rc;
			}
		}
	} else if (rc == -1)
		return -errno;
	return 0;
}

int lsv_chmod(const char *path, mode_t mode) {
	int rc;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	rc = chmod(path_name, mode);
	if (rc == -1)
		return -errno;

	return 0;
}

int lsv_chown(const char *path, uid_t uid, gid_t gid) {
	int rc;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	rc = lchown(path_name, uid, gid);
	if (rc == -1)
		return -errno;

	return 0;
}

int lsv_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
		off_t offset, struct fuse_file_info *fi) {
	DIR *dp;
	struct dirent *de;

	(void) offset;
	(void) fi;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	dp = opendir(path_name);
	if (dp == NULL)
		return -errno;

	while ((de = readdir(dp)) != NULL) {
		struct stat st;
		memset(&st, 0, sizeof(st));
		st.st_ino = de->d_ino;
		st.st_mode = de->d_type << 12;
		if (filler(buf, de->d_name, &st, 0))
			break;
	}

	closedir(dp);
	return 0;
}

int lsv_truncate(const char *path, off_t size) {
	lsv_s32_t rc = 0;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("truncate:%s\n", path_name);

	rc = truncate(path_name, size);
	if (rc == -1)
		return -errno;

	return 0;
}

static int lsv_utimens(const char *path, const struct timespec ts[2]) {
	int rc;
	char path_name[LSV_MAX_STRING_LEN];
	struct timeval tv[2];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("utimens:%s\n", path_name);
	/* don't use utime/utimes since they follow symlinks */

	tv[0].tv_sec = ts[0].tv_sec;
	tv[0].tv_usec = ts[0].tv_nsec / 1000;
	tv[1].tv_sec = ts[1].tv_sec;
	tv[1].tv_usec = ts[1].tv_nsec / 1000;

	rc = utimes(path_name, tv);
	if (rc == -1)
		return -errno;

	return 0;
}

int _volume_proto_readpage_lsv(lsv_volume_proto_t *volume_proto,
		lsv_u64_t offset, lsv_u32_t size, buffer_t *append_buf) {
	int rc = 0;
	lsv_u32_t chunk_id, chunk_offset;
	lsv_s32_t page_offset = 0;

	YASSERT(size<=LSV_PAGE_SIZE);

	rc = lsv_wbuffer_readpage(volume_proto, offset, size, append_buf);
	if (rc > 0) {
		DINFO("read:wbuffer_readpage:%d\n", rc);
		goto ret;
	}


	rc = lsv_rcache_page_lookup(volume_proto, offset, size, append_buf);
	if(rc > 0){
		DINFO("read:rcache_page_lookup:%d\n",rc);
	}

	lsv_bitmap_lock(volume_proto);
	rc = lsv_bitmap_paged_lookup(volume_proto,
			offset - offset % LSV_WBUF_PAGE_SIZE, &chunk_id, &chunk_offset);
	DINFO("read:bitmap lookup:rc:%d, chunk_id:%u, chunk_offset:%u\n", rc,
			chunk_id, chunk_offset);
	if (rc < 0) {
		DERROR("bitmap_paged_lookup err.errno:%d\n", rc);
		goto unlock_ret;
	}

	if (chunk_id > 0) {
		rc = lsv_rcache_lookup(volume_proto, chunk_id, chunk_offset,
				offset, size, NULL, append_buf);
		if (rc < 0) {
			DERROR("rcache_lookup err.errno:%d\n", rc);
			goto unlock_ret;
		}
	} else {
		DINFO("read:chunk_id ==== 0\n");
		rc = 0;
	}

	unlock_ret: lsv_bitmap_unlock(volume_proto);
	ret: return rc;
}

int volume_proto_read_lsv_(lsv_volume_proto_t *lsv_info, const io_t *io,
		buffer_t *buf) {
	int rc = 0;
	lsv_u64_t offset;
	lsv_u32_t size, left;
	lsv_u32_t read_count = 0;

	offset = io->offset;
	left = io->size;
	while (left > 0) {
		size = LSV_PAGE_SIZE - offset % LSV_PAGE_SIZE;
		size = left < size ? left : size;

		rc = _volume_proto_readpage_lsv(lsv_info, offset, size, buf);
		if (rc < 0) {
			DERROR("readpage_lsv err.errno:%d\n", rc);
			goto ret;
		}
		read_count += rc;

		offset += size;
		left -= size;
	}

	rc = read_count;
	DINFO("read:exit:%d\n", read_count);
	ret: return rc;
}

int lsv_read(const char *path, char *_buf, size_t size, off_t offset,
		struct fuse_file_info *fi) {
	int rc = 0, i = 0;
	lsv_u32_t chunk_id, chunk_offset;
	lsv_u32_t front_size, end_size;
	lsv_u64_t off = 0;
	ino_t ino;
	int read_count = 0;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;
	io_t io;
	buffer_t buf;

	char path_name[LSV_MAX_STRING_LEN];
	char page_buf[LSV_PAGE_SIZE];
	char *buf_t = NULL;
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_read :<%llu,%u>\n", offset, size);

	rc = stat(path_name, &stbuf);
	ino = stbuf.st_ino;
	rc = lsv_volumep_lookup(ino, &volume_proto);
	if (rc < 0) {
		return rc;
	}

	mbuffer_init(&buf, 0);
	io_init(&io,0, NULL, offset, size, 0);

	rc=volume_proto_read_lsv_(volume_proto, &io, &buf);

	mbuffer_get(&buf, _buf, buf.len);

	mbuffer_free(&buf);

	return rc;
}

int _volume_proto_writepage_lsv(lsv_volume_proto_t *volume_proto,
		lsv_u64_t offset, lsv_u32_t size, buffer_t *pop_buf) {
	int rc = 0;
	lsv_s32_t page_before = 0, page_after = 0;
	lsv_u64_t off_start = 0;
	buffer_t page_buf;

	YASSERT(size<=LSV_PAGE_SIZE);

	mbuffer_init(&page_buf, 0);
	page_before = offset % LSV_PAGE_SIZE;
	page_after = LSV_PAGE_SIZE - size - page_before;
	off_start = offset - page_before;

	if (page_before > 0) {
		rc = _volume_proto_readpage_lsv(volume_proto, off_start, page_before,
				&page_buf);
		if (rc < 0) {
			DERROR("readpage_lsv err.errno:%d\n", rc);
			goto ret;
		}
	}
	rc = mbuffer_pop(pop_buf, &page_buf, size);
	if (rc < 0) {
		DERROR("mbuffer_pop err.errno:%d\n", rc);
		goto ret_free;
	}
	if (page_after > 0) {
		rc = _volume_proto_readpage_lsv(volume_proto, offset + size, page_after,
				&page_buf);
		if (rc < 0) {
			DERROR("readpage_lsv err.errno:%d\n", rc);
			goto ret_free;
		}
	}

	rc = lsv_wbuffer_insert(volume_proto, off_start, LSV_PAGE_SIZE, &page_buf);

	ret_free: mbuffer_free(&page_buf);
	ret: return rc;
}

int volume_proto_write_lsv_(lsv_volume_proto_t *lsv_info, const io_t *io,
		const buffer_t *buf) {
	int rc = 0;
	lsv_u64_t offset;
	lsv_u32_t size, left;
	lsv_u32_t write_count = 0;

	offset = io->offset;
	left = io->size;
	while (left > 0) {
		size = LSV_PAGE_SIZE - offset % LSV_PAGE_SIZE;
		size = left < size ? left : size;

		rc = _volume_proto_writepage_lsv(lsv_info, offset, size, buf);
		if (rc < 0) {
			DERROR("writepage_lsv err.errno:%d\n", rc);
			goto ret;
		}
		write_count += rc;

		offset += size;
		left -= size;
	}

	rc = write_count;
	DINFO("write:exit:%d\n", write_count);
	ret: return rc;
}

int lsv_write(const char *path, const char *_buf, size_t size, off_t offset,
		struct fuse_file_info *fi) {
	int rc = 0;
	off_t page_offset = 0;
	lsv_u32_t chunk_id, chunk_offset;
	ino_t ino;
	lsv_u64_t tmp_size, file_size;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;
	io_t io;
	buffer_t buf;

	char path_name[LSV_MAX_STRING_LEN];
	char page_buf[LSV_PAGE_SIZE];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	DINFO("lsv_write :<%llu,%u>\n", offset, size);

	rc = stat(path_name, &stbuf);
	ino = stbuf.st_ino;
	file_size = stbuf.st_size;
	rc = lsv_volumep_lookup(ino, &volume_proto);
	if (rc < 0) {
		return rc;
	}

	mbuffer_init(&buf, 0);
	mbuffer_copy(&buf, _buf, size);
	io_init(&io, 0, NULL, offset, size, 0);

	rc=volume_proto_write_lsv_(volume_proto, &io, &buf);

	mbuffer_free(&buf);

	return rc;
}

int lsv_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
		unsigned int flags, void *snapshotname) {
	int rc = 0;
	ino_t ino;
	struct stat stbuf;
	lsv_volume_proto_t *volume_proto = NULL;

	char path_name[LSV_MAX_STRING_LEN];
	sprintf(path_name, "%s/%s", LSV_VOLUME_STORAGE_META_DIR, path);

	rc = stat(path_name, &stbuf);
	ino = stbuf.st_ino;
	rc = lsv_volumep_lookup(ino, &volume_proto);
	if (rc < 0) {
		return rc;
	}

	DINFO("lsv_ioctl:enter:%s, snapshot_name:%s\n", path_name, snapshotname);

	switch (cmd) {
	case LSV_CREATE_SNAPSHOT:
		DINFO("lsv_ioctl:create snapshot:%s\n", snapshotname)
		;
		lsv_bitmap_create_snapshot(volume_proto, NULL, (char *) snapshotname,
		NULL);
		return 0;
	case LSV_REVERT_SNAPSHOT:
		DINFO("lsv_ioctl:revert snapshot:%s\n", snapshotname)
		;
		lsv_bitmap_revert_snapshot(volume_proto, (char *) snapshotname);
		return 0;
	case LSV_DELETE_SNAPSHOT:
		DINFO("lsv_ioctl:delete snapshot:%s\n", snapshotname)
		;
		lsv_bitmap_delete_snapshot(volume_proto, (char*) snapshotname);
		return 0;
	case LSV_PRINT_SNAPSHOT:
		DINFO("lsv_ioctl:print snapshot:%s\n", snapshotname)
		;
		lsv_bitmap_print_tree(volume_proto);
		return 0;

	}

	return -EINVAL;
}

int lsv_initialize(lsv_volume_proto_t *volume_proto, lsv_u32_t flag) {
	lsv_s32_t rc = 0;
	lsv_u32_t first_chkid;

	DINFO("lsv_init:volume ino:%llu,flag:%u\n", volume_proto->ino, flag);
	if (flag == LSV_SYS_CREATE) {
		rc = lsv_volume_init(volume_proto, LSV_SYS_CREATE);
		if (rc < 0) {
			DINFO("lsv_init:create volume error:%d\n", rc);
			return rc;
		}

		rc = lsv_volume_chunk_malloc(volume_proto, LSV_PRIM_CHUNK_TYPE,
				&first_chkid);
		if (rc < 0 || 0 != first_chkid) {
			DINFO("lsv_init:malloc  first chunk error:%d\n", rc);
			return rc;
		}

		rc = lsv_log_init(volume_proto, LSV_SYS_CREATE);
		if (rc < 0) {
			DINFO("lsv_init:init log error:%d\n", rc);
			return rc;
		}

		rc = lsv_bitmap_init(volume_proto, LSV_SYS_CREATE, 0);
		if (rc < 0) {
			DINFO("lsv_init:init bitmap error:%d\n", rc);
			return rc;
		}

		rc = lsv_wbuffer_init(volume_proto, LSV_SYS_CREATE);
		if (rc < 0) {
			DINFO("lsv_init:init wbuffer error:%d\n", rc);
			return rc;
		}

		rc = lsv_rcache_init(volume_proto);
		if (rc < 0) {
			DINFO("lsv_init:init rcache error:%d\n", rc);
			return rc;
		}

		volume_proto->u.system_power_on = 1;
		rc = lsv_volumep_dump(volume_proto);
		if (rc < 0) {
			DINFO("lsv_init:update volume error:%d\n", rc);
			return rc;
		}
	} else if (flag == LSV_SYS_LOAD) {
		DINFO("volume:%x\n", volume_proto);
		rc = lsv_volume_init(volume_proto, LSV_SYS_LOAD);
		if (rc < 0) {
			DINFO("lsv_init:create volume error:%d\n", rc);
			return rc;
		}

		rc = lsv_log_init(volume_proto, LSV_SYS_LOAD);
		if (rc < 0) {
			DINFO("lsv_init:init log error:%d\n", rc);
			return rc;
		}

		rc = lsv_bitmap_init(volume_proto, LSV_SYS_LOAD, 0);
		if (rc < 0) {
			DINFO("lsv_init:init bitmap error:%d\n", rc);
			return rc;
		}

		rc = lsv_wbuffer_init(volume_proto, LSV_SYS_LOAD);
		if (rc < 0) {
			DINFO("lsv_init:init wbuffer error:%d\n", rc);
			return rc;
		}

		rc = lsv_rcache_init(volume_proto);
		if (rc < 0) {
			DINFO("lsv_init:init rcache error:%d\n", rc);
			return rc;
		}

		volume_proto->u.system_power_on = 1;
		rc = lsv_volumep_dump(volume_proto);
		if (rc < 0) {
			DINFO("lsv_init:update volume error:%d\n", rc);
			return rc;
		}

	} else {
		DINFO("lsv_init:init volume error:%d\n", rc);
	}

	return rc;
}

int lsv_finalize_vp(lsv_volume_proto_t *volume_proto) {
	lsv_s32_t rc = 0;

	rc = lsv_wbuffer_flush(volume_proto);
	if (rc < 0) {
		return rc;
	}

	rc = lsv_wbuffer_release(volume_proto);
	if (rc < 0) {
		return rc;
	}
	rc = lsv_rcache_release(volume_proto);
	if (rc < 0) {
		return rc;
	}

	rc = lsv_bitmap_deinit(volume_proto);
	if (rc < 0) {
		return rc;
	}

	rc = lsv_log_delete(volume_proto);
	if (rc < 0) {
		return rc;
	}

	rc = lsv_volume_delete(volume_proto);
	if (rc < 0) {
		return rc;
	}

	free(volume_proto);

	return rc;
}

int lsv_finalize(void) {
	lsv_s32_t rc = 0;
	struct list_head *index = NULL, *head = NULL;
	lsv_volume_proto_t *tmp = NULL;

	DINFO("finalize:%d,exit\n", rc);

	head = &lsv_volume_proto_head;

	list_for_each(index, head)
	{
		tmp = (lsv_volume_proto_t *) index;

		rc = lsv_wbuffer_flush(tmp);
		if (rc < 0) {
			continue;
		}

		rc = lsv_log_download(tmp);
		if (rc < 0) {
			continue;
		}

		rc = lsv_bitmap_deinit(tmp);
		if (rc < 0) {
			continue;
		}

		rc = lsv_volume_download(tmp);
		if (rc < 0) {
			continue;
		}

		tmp->u.system_power_on = 0;

		rc = lsv_volumep_dump(tmp);
		if (rc < 0) {
			DINFO("lsv_finalize:update volume error:%d\n", rc);
			return rc;
		}
	}
	return rc;
}

struct fuse_operations lsv_oper = { .statfs = lsv_statfs, .open = lsv_open,
		.access = lsv_access, .mknod = lsv_mknod, .read = lsv_read, .write =
				lsv_write, .unlink = lsv_unlink, .flush = lsv_flush, .release =
				lsv_release, .getattr = lsv_getattr, .chmod = lsv_chmod,
		.chown = lsv_chown, .truncate = lsv_truncate, .utimens = lsv_utimens,
		.readdir = lsv_readdir, .ioctl = lsv_ioctl, };

/*This is end of lsv_op.c*/
